#include "MetadataClase.h"

namespace Comun
{

		MetadataClase::MetadataClase(){}

		void MetadataClase::setClase(string Clase){
			_Clase=Clase;
		}

		void MetadataClase::setOrganizacionReg(OrgRegistros OrgReg){
			_OrganizacionReg=OrgReg;
		}

		void MetadataClase::addAtributo(const AtributoClase& atr){
			_Atributos.push_back(atr);
		}

		void MetadataClase::addRelacionIntegridad(const RelacionIntegridad& RI){
			_RelacionesIntegridad.push_back(RI);
		}

		void MetadataClase::setIndicePrimario(InfoIndice* IndicePrim){
			_IndicePrimario=IndicePrim;
		}

		void MetadataClase::addIndiceSecundario(InfoIndice* IndiceSec){
			_IndicesSecundarios.push_back(IndiceSec);
		}

		string MetadataClase::getClase(){
			return _Clase;
		}

		OrgRegistros MetadataClase::getOrganizacionReg(){
			return _OrganizacionReg;
		}

		list<AtributoClase>& MetadataClase::getAtributos(){
			return _Atributos;
		}

		list<RelacionIntegridad>& MetadataClase::getRelacionesIntegridad(){
			return _RelacionesIntegridad;
		}

		InfoIndice* MetadataClase::getIndicePrimario(){
			return _IndicePrimario;
		}

		list<InfoIndice*>& MetadataClase::getIndicesSecundarios(){
			return _IndicesSecundarios;
		}

		TipoRegistro MetadataClase::getTipoAtributo(string nombreAtrib){
			for (list<AtributoClase>::iterator it=getAtributos().begin();it!=getAtributos().end();++it){
				if (it->getNombre()==nombreAtrib)
					return it->getTipo();
			}
			cerr << "CapaIndices->MetadataClase.cpp->MetadataClase::getTipoAtributo(string nombreAtrib)" << endl << "Tipo inexistente." << endl;
			throw new exception();
		}

		MetadataClase::~MetadataClase(){
			_Atributos.clear();
			_IndicesSecundarios.clear();
		}

		bool MetadataClase::hayIndiceCampo(string NombreCampo){
			if (campoExiste(NombreCampo)){
				if (esIndicePrimario(NombreCampo)){
					return true;
				}else{
					return esIndiceSecundario(NombreCampo);
				}
			}else
				return false;
		}

		bool MetadataClase::esIndicePrimario(string NombreCampo){
			if (_IndicePrimario->getCampos().size()>1){
				//indice compuesto
				return false;
			}else{
				return (_IndicePrimario->getCampos().front()==NombreCampo);
			}
		}

		bool MetadataClase::esIndiceSecundario(string NombreCampo){
			list<InfoIndice*>::iterator it=_IndicesSecundarios.begin();
			bool encontrado=false;
			while ((it!=_IndicesSecundarios.end()) && (!encontrado)){
				if ((*it)->getCampos().size()==1){
					encontrado =((*it)->getCampos().front()==NombreCampo);
				}
				++it;
			}
			return encontrado;
		}

		bool MetadataClase::campoExiste(string NombreCampo){
			list<AtributoClase>::iterator it=_Atributos.begin();
			bool encontrado=false;
			while ((it!=_Atributos.end()) && (!encontrado)){
				encontrado=((*it).getNombre()==NombreCampo);
				++it;
			}
			return encontrado;
		}

		MetadataClase* MetadataClase::hidratarDesdeStream(stringstream* streamInfo){
			MetadataClase* MC=new MetadataClase();

			string str;
			string valores[10];
			if (streamInfo->eof())
			{
				cerr << "CapaIndices->MetadataClase.cpp->MetadataClase::hidratar(list<string> ListaInfo)" << endl << "Metadata de clase Invalida" << endl;
				throw new exception();
			}

			getline(*streamInfo,str);
			

			if (str=="[definicionTipo]"){
				getline(*streamInfo,str); //leo clase
				MC->setClase(hidratarNombreClase(str));  //seteo la clase
				getline(*streamInfo,str); // espacio en blanco
				getline(*streamInfo,str); //leo titular
			}else{
				cerr << "CapaIndices->MetadataClase.cpp->MetadataClase::hidratar(list<string> ListaInfo)" << endl << "Archivo no valido, no se encontro [definicionTipo]" << endl;
				throw new exception();
			}

			if (str=="[organizacionRegistro]"){
				getline(*streamInfo,str); //leo clase
				MC->setOrganizacionReg(hidratarOrganizaciondeReg(str));  //seteo la clase
				getline(*streamInfo,str);// espacio en blanco
				getline(*streamInfo,str); //leo titular
			}else{
				cerr << "CapaIndices->MetadataClase.cpp->MetadataClase::hidratar(list<string> ListaInfo)" << endl << "Archivo no valido, no se encontro [organizacionRegistro]." << endl;
				throw new exception();
			}

			if (str=="[definicionAtributos]"){
				getline(*streamInfo,str);
				while (str.length()>0){
					for (int i=0;i<2;++i){
						valores[i] = str;
						getline(*streamInfo,str); //leo el atributo
					}
					MC->addAtributo(hidratarAtributo(valores)); //agrego la condicion
				}
				getline(*streamInfo,str); //leo el titular
			}

			if (str=="[definicionIndices]"){
				getline(*streamInfo,str); //leo el titular
				if (str=="[griego]"){
					getline(*streamInfo,str); //leo el atributo
					int i=0;
					while (str.length()>0){
						valores[i] = str;
						getline(*streamInfo,str); //leo el atributo
						++i;
					}
					MC->setIndicePrimario(hidratarIndice(valores,true)); //agrego los datos
					getline(*streamInfo,str); //leo siguiente a esp en blanco
				}
				//lectura de romanos
				if (str=="[romanos]"){
					getline(*streamInfo,str); //leo atributo de indice o titular
					while ((!(str=="[Integridad]")) && (str.length()>0)){
						int i=0;
						while (str.length()>0){
							valores[i] = str;
							getline(*streamInfo,str); //leo el atributo
							++i;
						}

						MC->addIndiceSecundario(hidratarIndice(valores,false)); //agrego los datos
						getline(*streamInfo,str); //leo siguiente a esp en blanco
					}
				}
			}

			if (str=="[Integridad]"){			
				getline(*streamInfo,str); //leo campos
				while ((!streamInfo->eof())  &&(str.length()>0)){					
					for (int i=0;i<4;++i){
						valores[i]=str;
						getline(*streamInfo,str);
					}
					MC->addRelacionIntegridad(hidratarRelacionIntegridad(valores)); //agrego los datos
				}
			}
			return MC;
		}

		MetadataClase* MetadataClase::hidratarDesdeLista(list<string> ListaInfo){
			MetadataClase* MC=new MetadataClase();

			string str;
			string valores[10];
			list<string>::iterator it=ListaInfo.begin();
			if (it==ListaInfo.end())
			{
				cerr << "CapaIndices->MetadataClase.cpp->MetadataClase::hidratar(list<string> ListaInfo)" << endl << "Metadata de clase Invalida" << endl;
				throw new exception();
			}

			str=*(it++);

			if (str=="[definicionTipo]"){
				str=*(it++); //leo clase
				MC->setClase(hidratarNombreClase(str));  //seteo la clase
				str=*(it++); // espacio en blanco
				str=*(it++); //leo titular
			}else{
				cerr << "CapaIndices->MetadataClase.cpp->MetadataClase::hidratar(list<string> ListaInfo)" << endl << "Archivo no valido, no se encontro [definicionTipo]" << endl;
				throw new exception();
			}

			if (str=="[organizacionRegistro]"){
				str=*(it++); //leo clase
				MC->setOrganizacionReg(hidratarOrganizaciondeReg(str));  //seteo la clase
				str=*(it++); // espacio en blanco
				str=*(it++); //leo titular
			}else{
				cerr << "CapaIndices->MetadataClase.cpp->MetadataClase::hidratar(list<string> ListaInfo)" << endl << "Archivo no valido, no se encontro [organizacionRegistro]." << endl;
				throw new exception();
			}

			if (str=="[definicionAtributos]"){
				str=*(it++);
				while (str.length()>0){
					for (int i=0;i<2;++i){
						valores[i] = str;
						str=*(it++); //leo el atributo
					}
					MC->addAtributo(hidratarAtributo(valores)); //agrego la condicion
				}
				str=*(it++); //leo el titular
			}

			if (str=="[definicionIndices]"){
				str=*(it++); //leo el titular
				if (str=="[griego]"){
					str=*(it++); //leo el atributo
					int i=0;
					while (str.length()>0){
						valores[i] = str;
						str=*(it++); //leo el atributo
						++i;
					}
					MC->setIndicePrimario(hidratarIndice(valores,true)); //agrego los datos
					str=*(it++); //leo siguiente a esp en blanco
				}
				//lectura de romanos
				if (str=="[romanos]"){
					str=*(it++); //leo atributo de indice o titular
					while ((!(str=="[Integridad]")) && (str.length()>0)){
						int i=0;
						while (str.length()>0){
							valores[i] = str;
							str=*(it++); //leo el atributo
							++i;
						}

						MC->addIndiceSecundario(hidratarIndice(valores,false)); //agrego los datos
						str=*(it++); //leo siguiente a esp en blanco
					}
				}
			}

			if (str=="[Integridad]"){
				while ((str.length()>0)&&(it!=ListaInfo.end())){
					str=*(it++); //leo campos
					valores[0]=str;
					for (int i=1;i<4;++i){
						str=*(it++);
						valores[i]=str;						
					}
					MC->addRelacionIntegridad(hidratarRelacionIntegridad(valores)); //agrego los datos
				}
			}
			return MC;
		}


		ImplementIndice MetadataClase::hidratarTipoIndice(string str){
			str=str.substr(13);
			if (str=="Hash"){
				return iHash;
			}else if (str=="ArbolB+"){
				return iArbolBPlus;
			}else{
				cerr << "CapaIndices->MetadataClase.cpp->MetadataClase::hidratarTipoIndice(string str)" << endl << "TipoIndice invalido." << endl;
				throw new exception();
			}
		}

		OrgRegistros MetadataClase::hidratarOrganizaciondeReg(string str){
			str=str.substr(24);
			if (str=="RVB"){
				return iRVB;
			}else if (str=="RF"){
				return iRF;
			}else{
				cerr << "CapaIndices->MetadataClase.cpp->MetadataClase::hidratarOrganizaciondeReg(string str)" << endl << "TipoOrg invalido." << endl;
				throw new exception();
			}
		}

		AtributoClase MetadataClase::hidratarAtributo(string val[]){
			AtributoClase atr;
			atr.setNombre(val[0].substr(17));
			atr.setTipo(hidratarTipoVar(val[1]));
			return atr;
		}

		TipoRegistro MetadataClase::hidratarTipoVar(string str){
			str=str.substr(15);
			if (str=="String"){
				return Cadena;
			}else if (str=="Booleano"){
				return Booleano;
			}else if (str=="Entero corto"){
				return Entero;
			}else if (str=="Caracter"){
				return Caracter;
			}else if (str=="Entero"){
				return EnteroLargo;
			}else if (str=="Real"){
				return Real;
			}else if (str=="Fecha"){
				return Fecha;
			}else{
				cerr << "CapaIndices->MetadataClase.cpp->MetadataClase::hidratarTipoVar(string str)" << endl << "Tipovar invalido." << endl;
				throw new exception();
			}

		}

		InfoIndice* MetadataClase::hidratarIndice(string val[],bool Primario){
			InfoIndice* Index=new InfoIndice;
			Index->setPrimario(Primario);
			string Campo;
			int TamanioNodo;
			unsigned int TamanioInicial;
			int TamanioBucket;
			int sig=0;
			ImplementIndice TIndex=hidratarTipoIndice(val[0]);
			switch (TIndex){
				case iArbolBPlus:
					TamanioNodo=atoi(val[1].substr(19).c_str());
					Index->setArbolBP(TamanioNodo);
					sig=2;
					break;
				case iHash:
					TamanioInicial=atoi(val[1].substr(16).c_str());
					TamanioBucket=atoi(val[2].substr(15).c_str());
					Index->setHash(TamanioInicial,TamanioBucket);
					sig=3;
					break;
			}

			while ((val[sig].length()>0) && (sig<10)){
				Index->addCampo(val[sig++].substr(14));
			}
			return Index;
		}

		string MetadataClase::hidratarNombreClase(string str){
			return str.substr(13);
		}

		RelacionIntegridad MetadataClase::hidratarRelacionIntegridad(string val[]){
			RelacionIntegridad RI;
			RI.setNombreCampo(val[0].substr(12));
			RI.setNombreClase(val[1].substr(18));
			RI.setNombreCampoClaseExterna(val[2].substr(18));
			RI.setTipoIntegridad(hidratarTipoIntegridad(val[3]));
			return RI;
		}

		TipoIntegridad MetadataClase::hidratarTipoIntegridad(string val){
			val=val.substr(17);
			if (val=="Alta"){
				return iAlta;
			}else{
				return iBaja;				
			}					
		}

}
